Built for 𝕏∙LinkedIn∙Bluesky∙Threads. Powered by AI
Write & schedule, effortlessly
Craft and publish engaging content in an app built for creators.
NEW
Publish anywhere
Publish on X, LinkedIn, Bluesky, Threads, & Mastodon at the same time.
Make it punchier 👊
Typefully
@typefully
We're launching a Command Bar today with great commands and features.
AI ideas and rewrites
Get suggestions, tweet ideas, and rewrites powered by AI.
Turn your tweets & threads into a social blog
Give your content new life with our beautiful, sharable pages. Make it go viral on other platforms too.
+14
Followers
Powerful analytics to grow faster
Easily track your engagement analytics to improve your content and grow faster.
Build in public
Share a recent learning with your followers.
Create engagement
Pose a thought-provoking question.
Never run out of ideas
Get prompts and ideas whenever you write - with examples of popular tweets.
@aaditsh
I think this thread hook could be improved.
@frankdilo
On it 🔥
Share drafts & leave comments
Write with your teammates and get feedback with comments.
NEW
Easlo
@heyeaslo
Reply with "Notion" to get early access to my new template.
Jaga
@kandros5591
Notion 🙏
DM Sent
Create giveaways with Auto-DMs
Send DMs automatically based on engagement with your tweets.
And much more:
Auto-Split Text in Posts
Thread Finisher
Tweet Numbering
Pin Drafts
Connect Multiple Accounts
Automatic Backups
Dark Mode
Keyboard Shortcuts
Creators love Typefully
180,000+ creators and teams chose Typefully to curate their Twitter presence.
Marc Köhlbrugge@marckohlbrugge
Tweeting more with @typefully these days.
🙈 Distraction-free
✍️ Write-only Twitter
🧵 Effortless threads
📈 Actionable metrics
I recommend giving it a shot.
Jurre Houtkamp@jurrehoutkamp
Typefully is fantastic and way too cheap for what you get.
We’ve tried many alternatives at @framer but nothing beats it. If you’re still tweeting from Twitter you’re wasting time.
DHH@dhh
This is my new go-to writing environment for Twitter threads.
They've built something wonderfully simple and distraction free with Typefully 😍
Santiago@svpino
For 24 months, I tried almost a dozen Twitter scheduling tools.
Then I found @typefully, and I've been using it for seven months straight.
When it comes down to the experience of scheduling and long-form content writing, Typefully is in a league of its own.
Luca Rossi ꩜@lucaronin
After trying literally all the major Twitter scheduling tools, I settled with @typefully.
Killer feature to me is the native image editor — unique and super useful 🙏
Visual Theory@visualtheory_
Really impressed by the way @typefully has simplified my Twitter writing + scheduling/publishing experience.
Beautiful user experience.
0 friction.
Simplicity is the ultimate sophistication.
Queue your content in seconds
Write, schedule and boost your tweets - with no need for extra apps.
Schedule with one click
Queue your post with a single click - or pick a time manually.
Pick the perfect time
Time each post to perfection with Typefully's performance analytics.
Boost your content
Retweet and plug your posts for automated engagement.
Start creating a content queue.
Write once, publish everywhere
We natively support multiple platforms, so that you can expand your reach easily.
Check the analytics that matter
Build your audience with insights that make sense.
Writing prompts & personalized post ideas
Break through writer's block with great ideas and suggestions.
Never run out of ideas
Enjoy daily prompts and ideas to inspire your writing.
Use AI for personalized suggestions
Get inspiration from ideas based on your own past tweets.
Flick through topics
Or skim through curated collections of trending tweets for each topic.
Write, edit, and track tweets together
Write and publish with your teammates and friends.
Share your drafts
Brainstorm and bounce ideas with your teammates.
NEW
@aaditsh
I think this thread hook could be improved.
@frankdilo
On it 🔥
Add comments
Get feedback from coworkers before you hit publish.
Read, Write, Publish
Read, WriteRead
Control user access
Decide who can view, edit, or publish your drafts.
Esto es el ROLECE: el Registro Oficial de Licitadores y Empresas Clasificadas del Estado. Es un registro público de contratistas.
🚀 Quiero descargármelo para cruzarlo con los datos de contratación pública
🚫 Problema: el ROLECE no se puede descargar
…O no se «podía» 😆
🧵👇
El acceso al ROLECE es bajo certificado digital. Pero si accedes, no puedes consultar el listado. Solo puedes ver tu propia inscripción.
🔗 registrodelicitadores.gob.es/rolecet.co/07DhRMvIRi
Es la transparencia de Schrödinger: transparente y opaco a la vez. 🤷
El art. 344 de la Ley de Contratos del Sector Público (LCSP) establece que el ROLECE «será público y se podrá acceder de forma abierta previa identificación». Y que un reglamento «determinará modalidades y requisitos para la publicidad del Registro».
Pero no hay nada. 💩
El buscador de Hacienda tiene seis campos. Solo uno es obligatorio: el nombre del contratista. Pero yo no quiero acceder al expediente de un contratista: ¡quiero acceder A TODOS!
Para cruzarlos informáticamente con la PLCSP y dar más transparencia a la contratación pública.
El buscador me obliga a consignar un mínimo de cuatro letras del nombre del contratista. ¿Por qué hacen esto? ¡Qué ganas de entorpecer el acceso a los datos públicos!
Puedo buscar «ZARA» o «IKEA». O Puedo teclear «FERRE» y encontrar todas las ferreterías.
Podría descargar todo el listado por fuerza bruta, automatizando búsquedas iterativas:
AAAA
AAAB
AAAC
…
ZZZX
ZZZY
ZZZZ
Pero sería una cochinada ineficiente:
26×26×26×26 = 456.976 búsquedas
Tiene que haber otra manera.
La validación de los datos de entrada de un formulario web puede hacerse en dos puntos del ciclo petición-respuesta:
1️⃣ En el cliente (el navegador del usuario); o,
2️⃣ En el servidor (la aplicación de Hacienda).
Siempre se recomienda validar los datos al menos en el servidor.
Observo que el buscador de Hacienda valida los datos en el cliente. Mi única esperanza es que no estén haciendo validación también en el servidor.
Juego todo a esta carta y comienzo a inspeccionar el campo de entrada que me interesa: el nombre del contratista.
Tiene asociados dos manejadores de eventos:
1️⃣ Uno al evento «change», que se dispara cuando el campo cambia.
2️⃣ Otro al evento «keypress», que se dispara cuando el usuario presiona una tecla con el foco en el campo.
Me interesa el evento «change», que se dispara después de «keypress».
Invoca una función ValidatorOnChange()
Exploro la función, voy trazando el código…
…y llego a una segunda función: ValidatorUpdateIsValid()
Que parece devolver un valor booleano:
— «verdadero» si todos los campos del formulario son válidos.
— «falso» si alguno de los seis campos tiene errores.
Quiero modificar esta función. Pero si está encapsulada en un módulo, una clase o un objeto, será complicado hacer nada con ella…
Afortunadamente para mí, está definida en el «scope» global 🎉. ¡Esto significa que puedo redefinirla desde el confort de mi navegador! 😜
Vamos a ver si hay suerte…
Asigno a AllValidatorsValid una nueva función que toma la misma entrada pero que siempre devuelve «verdadero».
Y en el campo del formulario consigno un valor ilegal: «A».
¿Colará?
…Y CUELAAAAAAaaaa!!!!!!111unouno
🎉 Con esto puedo sortear la validación del formulario. YEAH!
Ahora tengo que ver cómo iterar por las 26 letras del abecedario y bajarme todas las páginas del tirón. 🤓
Observo las peticiones al servidor y encuentro una llamada GET por XHR (Ajax).…
…a la que el servidor responde un JSON con los datos de mi interés.
✅ Son datos públicos.
✅ De un registro público.
✅ Que sirve Hacienda en internet.
Esto no es ningún crimen. ¡Es liberar datos públicos para que haya más transparencia en la contratación pública!
Replico la petición desde la línea de comandos, con cURL. Encuentro los parámetros que controlan el número de resultados por respuesta y la paginación de los resultados.
Con la letra «A» hay 9.953 registros, lo que son exactamente 100 páginas de 100 elementos cada una.
Hay mil formas de hacer esto, pero opto por seguir en la terminal y usar «seq»:
$ seq 0 100 10000
Genero así los valores del parámetro «iDisplayStart», que controla dónde comienza cada página.
Un poco de bricolaje y ya tengo un cerdoscript… 🐷
Curiosamente el dato más importante, el término de búsqueda, no viaja en ningún parámetro de las peticiones XHR. Parece que el servidor lo almacena en una variable de sesión y lo recupera de una cookie.
Es kafkiano, pero me da igual porque en el script paso la cookie… 🤷
Vuelvo al campo de búsqueda.
Puedo iterar 27 veces con todas las letras del abecedario. Y, para cada una de ellas, iterar a su vez por el número de páginas de resultados.
Pero no quiero iterar tanto.
¿Qué puedo hacer?
Tengo que darle al servidor al menos un caracter que me devuelva todos los registros. Pero, ¿cuál?
Pruebo con el espacio en blanco. ¿Funcionará?
¡No funciona!
La aplicación debe de estar haciendo un trim() de la cadena de texto que yo le envío, para eliminar los espacios en blanco antes de determinar si el valor está vacío.
Pero, ¿y si les envío algo que parezca un espacio pero no lo sea?
Esto es el caracter Unicode U+2800: un espacio vacío en Braille. Al ojo humano es indistinguible de un espacio tecleado con la barra espaciadora. Pero quizá trim() sí lo distinga…
¿Servirá para confundir al servidor de Hacienda?
🔗 compart.com/en/unicode/U+2800
🚀 ¡HASTA LA COCINA!
Añado ocho filas más al cerdoscript y me reclino satisfecho en el estrado imaginario de mi putoamismo mientras descargan a mi portatil todos los registros.
¡Ahora tengo 10.747 expedientes más para cruzar con los datos de contratación! 🥳
Síganme para más recetas. 🤣